/****************************************************************************
 *
 *  ALi (Shanghai) Corporation, All Rights Reserved. 2007 Copyright (C)
 *
 *  File: pvr_mgr_common.c
 *
 *  Description: This file describes pvr manager layer common functions.
 *
 *  History:
 *      Date        	Author      	Version  		Comment
 *      ====        	======      	=======  		=======
 *  1.  2009.3.20  		Dukula_Zhu  	0.0.1  		
 *
 ****************************************************************************/
#include "pvr_mgr_data.h"
#include <hld/dmx/dmx.h>

static int __strnicmp(const char * cs, const char * ct, int count) 
{
    int c1, c2, res = 0;
    
    while (count) {
	c1 = *cs++; c2 = *ct++;
	if (c1 >= 'A' && c1 <= 'Z') c1 += 'a' - 'A';
	if (c2 >= 'A' && c2 <= 'Z') c2 += 'a' - 'A';
	if ((res = c1 - c2) != 0 || (!*cs && !*ct))
	    break;
	count--;
    }
    
    return res;
}

static int __pvr_mgr_strcmp_c(const char *s1, const char *s2)
{
	int i;
	char c1, c2;

	for (i = 0, c1 = *s1, c2 = *s2; (c1 != '\0') && (c2 != '\0'); i++)
	{
		c1 = *(s1 + i);
		c2 = *(s2 + i);
		if ((c1 >= 'A') && (c1 <='Z')) c1 += 'a' - 'A';
		if ((c2 >= 'A') && (c2 <='Z')) c2 += 'a' - 'A';
		if (c1 != c2) break;
	}

	return (int)c1 - (int)c2;
}


static INT32 __pvr_mgr_rm(const char *path)
{
	char mount_name[256];

	fs_remove(path);
	_pvr_mgr_get_mount_name(path, mount_name);
	_fsync(mount_name);
	return 0;
}

UINT16 _pvr_list_alloc_index(ppvr_mgr_list list)
{
	UINT16 ret = TMS_INDEX;
	struct list_head *ptr = NULL;
	ppvr_mgr_list_item item = NULL;
	
	list_for_each(ptr, &list->head)
	{
		item = list_entry(ptr, pvr_mgr_list_item, listpointer);
		if((item->f_type != F_DIR) && (item->record_info != NULL))
			ret = (item->record_info->record_idx > ret) ? item->record_info->record_idx : ret;
	}
	ret++;

	return ret;
}

static int __pvr_mgr_do_read_test(char *fname)
{
	int buffer_len = QUANTUM_SIZE;
	char *buffer ;
	uint32 tm1, tm2;
	int i;
	int temp_ret;
	FILE *file1 = NULL;
	
	file1 = _fopen(fname, "r");
	if(file1 == NULL)
	{
		return -1;
	}

	_pvr_mgr_malloc(buffer, buffer_len, 0);
	tm1 = osal_get_tick();
	for(i = 0 ; i < PVR_RW_TEST_TIMES; i++)
	{
		uint32 tmm = osal_get_tick();
		
		temp_ret = _fread(buffer, buffer_len, file1);
		if(temp_ret != buffer_len)
		{
			PERROR("read test error, ret = %d!\n", temp_ret);
			_fclose(file1);
			_pvr_mgr_free(buffer);
			return -2;
		}
	}
	// To get more precise speed, flush data to disk.
	_fclose(file1);
	_fsync(fname);

	tm2 = osal_get_tick();

	_pvr_mgr_free(buffer);
	
	return (QUANTUM_SIZE*PVR_RW_TEST_TIMES)/(tm2-tm1);
}

static int __pvr_mgr_do_write_test(char *fname)
{
	int buffer_len = QUANTUM_SIZE;
	char *buffer ;
	uint32 tm1, tm2;
	int i, seed;
	int temp_ret;
	FILE *file1 = NULL;

	file1 = _fopen(fname, "w");
	if(file1 == NULL)
	{
		__pvr_mgr_rm(fname);
		return -1;
	}
	
	_pvr_mgr_malloc(buffer, buffer_len, 0);

	for(i = 0; i < buffer_len; i++)
	{
		buffer[i] = RAND(0xff);		
	}
	tm1 = osal_get_tick();
		
	for(i = 0 ; i < PVR_RW_TEST_TIMES; i++)
	{
		uint32 tmm = osal_get_tick();
		
		temp_ret = _fwrite(buffer, buffer_len, file1);
		if(temp_ret != buffer_len)
		{
			PERROR("write test error, ret = %d!\n", temp_ret);
			_fclose(file1);
			_pvr_mgr_free(buffer);
			return -1;
		}
	}
	// To get more precise speed, flush data to disk.
	_fclose(file1);
	_fsync(fname);
	
	tm2 = osal_get_tick();

	_pvr_mgr_free(buffer);
	
	return (QUANTUM_SIZE*PVR_RW_TEST_TIMES)/(tm2-tm1);
}

static int __pvr_mgr_do_copy(char *fsrc, char *fdst)
{
	int buffer_len = QUANTUM_SIZE;
	char *buffer = NULL; 
	int i;
	int temp_ret;
	FILE *file1 = NULL, *file2 = NULL;
	uint32 tm1, tm2;

		
	file1 = _fopen(fdst, "w");
	if(file1 == NULL)
	{
		__pvr_mgr_rm(fdst);
		return -1;
	}

	file2 = _fopen(fsrc, "r");
	if(file2 == NULL)
	{
		PERROR("open file failed!\n");
		return -1;
		
	}
	_pvr_mgr_malloc(buffer, buffer_len, 0);

	tm1 = osal_get_tick();
	
	for(i = 0 ; i < PVR_RW_TEST_TIMES; i++)
	{
		temp_ret = _fread(buffer, buffer_len, file2);
		if(temp_ret != buffer_len)
		{
			PERROR("copy read test error, ret = %d!\n", temp_ret);
			_fclose(file1);
			_fclose(file2);
			_pvr_mgr_free(buffer);
			return -1;
		}
		temp_ret = _fwrite(buffer, buffer_len, file1);
		if(temp_ret != buffer_len)
		{
			PERROR("copy write test error, ret = %d!\n", temp_ret);			
			_fclose(file1);
			_fclose(file2);
			_pvr_mgr_free(buffer);
			return -1;
		}
	}
	// To get more precise speed, flush data to disk.
	_fclose(file1);
	_fclose(file2);
	_fsync(fdst);

	tm2 = osal_get_tick();

	_pvr_mgr_free(buffer);

	return (QUANTUM_SIZE*PVR_RW_TEST_TIMES)/(tm2-tm1);
}

/* Provides strncasecmp also (same thing) */
int _strncasecmp(const char *cs, const char *ct, int count)
{
    return __strnicmp(cs, ct, count);
}

/* Provides strncasecmp also (same thing) */
int _strcasecmp(const char *cs, const char *ct)
{
    int len_s = strlen(cs);
    int len_t = strlen(ct);
    if (len_s != len_t)
	return 1;
    return __strnicmp(cs, ct, len_s);
}

void _pvr_mgr_add_record_name(UINT8 *dest_name, UINT16 *src_name)
{
	UINT i;
	
	ComUniStrToAsc((UINT8 *)src_name, dest_name);

	// only enable letter and number and "- _" for name.
	for(i = 0; i < STRLEN(dest_name); i++)
	{
		if( (dest_name[i] >= 'a' && dest_name[i] <= 'z') ||
			(dest_name[i] >= 'A' && dest_name[i] <= 'Z') ||
			(dest_name[i] >= '0' && dest_name[i] <= '9') ||
			(dest_name[i] == ' ') || (dest_name[i] == '_') ||
			(dest_name[i] == '-'))
		{
			continue;		
		}
		dest_name[i] = 0;
	}
	if(i == 0)
	{
		STRCPY(dest_name,"null");
	}
	
}


BOOL _pvr_mgr_check_extname(const char *name, const char *ext_name)
{
	BOOL ret = FALSE;
	int j, k;
	
	for (j=0, k=-1; name[j] != '\0'; j++)
	{
		if (name[j] == '.') k = j;
	}
	if (k != -1)
	{
		if(!__pvr_mgr_strcmp_c(name + k, ext_name))
		{
			ret = TRUE;
		}
	}

	return ret;
}

void _pvr_mgr_get_mount_name(const char *full_path, char *mount_name)
{
	UINT32 i,j;

	mount_name[0] = 0;

	if(strncmp(full_path,"/mnt", 4) == 0)
	{
		// format: "/mnt/uda1/AliDVBS2"
		for(i = 0, j = 0; i < STRLEN((char *)full_path); i++)
		{
			if(full_path[i] == '/')
			{
				j++;
			}
			if(j == 3)
			{
				MEMCPY(mount_name, full_path, i);
				mount_name[i] = 0;
				break;
			}
		}

		if(j < 3)
		{
			STRCPY(mount_name, (char *)full_path);
		}
	}
	else
	{
		// format: "/c/AliDVBS2"
		for(i = 0, j = 0; i < STRLEN((char *)full_path); i++)
		{
			if(full_path[i] == '/')
			{
				j++;
			}
			if(j == 2)
			{
				MEMCPY(mount_name, (char *)full_path, i);
				mount_name[i] = 0;
				break;
			}
		}
		if(j < 2)
		{
			STRCPY(mount_name, (char *)full_path);
		}		
	}
}

BOOL _pvr_mgr_get_parent_dir(const char *name, const char *parent_name)
{
	BOOL ret = FALSE;
	int j, k;
	
	for (j=strlen(name)-1, k=-1; j>0; j--)
	{
		if (name[j] == '/') 
		{
			k = j;
			break;
		}
	}
	if (k != -1)
	{
		strncpy((char *)parent_name, name, j);
	}

	return ret;
}

BOOL _pvr_mgr_calc_fullpath(const char *path_prex, PREC_ENG_INFO info, PVR_FFORMAT_TYPE file_type, UINT32 file_idx, char *full_path)
{
	BOOL ret = TRUE;
	char string[256], temp[256];
	
	switch(file_type)
	{
		case PVR_TYPE_INFO:
			if(g_pvr_mgr_info->config.cfg_ext.pvr_mode == PVR_REC_SAME_FOLDER)
			{
				STRCPY(full_path, (char *)path_prex);
				strcat(full_path, ".");
			}
			else
			{
				STRCPY(full_path, (char *)path_prex);
				strcat(full_path, "/");
			}
			if(info->old_item == PVR_REC_ITEM_PVR3)
				strcat(full_path, g_pvr_mgr_info->config.info_file_name_new);
			else
				strcat(full_path, g_pvr_mgr_info->config.info_file_name);
			break;
		case PVR_TYPE_HEAD:
			if(g_pvr_mgr_info->config.cfg_ext.pvr_mode == PVR_REC_SAME_FOLDER)
			{
				STRCPY(temp, "_%03d.");
			}
			else
			{
				STRCPY(temp, "/%03d.");
			}
			
			if (info->data_version < PVR_DATA_VERSION_3)
			{
				strcat(temp, (info->rec_type==PVR_REC_TYPE_PS) ? g_pvr_mgr_info->config.ps_file_format : g_pvr_mgr_info->config.ts_file_format);
			}
			else
			{
				strcat(temp, g_pvr_mgr_info->config.ts_file_format);
			}
			sprintf(string, temp, file_idx);
			STRCPY(full_path, (char *)path_prex);
			strcat(full_path, string);
			break;
		case PVR_TYPE_DATA:
			if(g_pvr_mgr_info->config.cfg_ext.pvr_mode == PVR_REC_SAME_FOLDER)
			{
				STRCPY(temp, "_%03d.");
			}
			else
			{
				STRCPY(temp, "/%03d.");
			}			
			
			if (info->data_version < PVR_DATA_VERSION_3)
			{
				strcat(temp, (info->rec_type==PVR_REC_TYPE_PS) ? g_pvr_mgr_info->config.ps_file_format : g_pvr_mgr_info->config.ts_file_format);
			}
			else
			{
				strcat(temp, (info->rec_type==PVR_REC_TYPE_PS) ? g_pvr_mgr_info->config.ps_file_format : g_pvr_mgr_info->config.ts_file_format_new);
			}
			sprintf(string, temp, file_idx);
			STRCPY(full_path, (char *)path_prex);
			strcat(full_path, string);
			break;
		case PVR_TYPE_TEST:			
			STRCPY(full_path, (char *)path_prex);
			strcat(full_path, "/");
			strcat(full_path, (file_idx==1) ? g_pvr_mgr_info->config.test_file1 : g_pvr_mgr_info->config.test_file2);			
			break;
		case PVR_TYPE_PREX:
			STRCPY(full_path, (char *)path_prex);
			strcat(full_path, "/");
			strcat(full_path, g_pvr_mgr_info->config.dvr_path_prefix);
			break;

		case PVR_TYPE_VMX:
			if(g_pvr_mgr_info->config.cfg_ext.pvr_mode == PVR_REC_SAME_FOLDER)
			{
				STRCPY(full_path, (char *)path_prex);
				strcat(full_path, ".");
			}
			else
			{
				STRCPY(full_path, (char *)path_prex);
				strcat(full_path, "/");
			}
			strcat(full_path, g_pvr_mgr_info->config.storeinfo_file_name);
			break;

		default:
			break;
	}

	return ret;
}

void _pvr_mgr_get_local_time(struct PVR_DTM *tm)
{
	date_time dt;
	get_local_time(&dt);

	tm->mjd = dt.mjd ;
	tm->year = dt.year;
	tm->month = dt.month;
	tm->day = dt.day;
	tm->weekday = dt.weekday;
	tm->hour = dt.hour;
	tm->min = dt.min;
	tm->sec = dt.sec;
}


INT8 _pvr_mgr_event(PVR_HANDLE handle, UINT32 msg_type, UINT32 msg_code)
{
	INT8 ret = 0;
	ppvr_mgr_active_record record = NULL;
	ppvr_mgr_list_item item = NULL;
	UINT32 i = 0;

	if(handle != 0)
	{
		if(msg_type == PVR_MSG_REC_START_GET_HANDLE)
		{
			record = (ppvr_mgr_active_record)_pvr_update_record_handle(handle);
			return ret;
		}
		else if(msg_type == PVR_MSG_PLAY_START_GET_HANDLE)
		{
			record =(ppvr_mgr_active_record) _pvr_update_play_handle(handle);
		}
		else
		{
			record = _pvr_get_record_byhandle(handle);
		}
		pvr_return_val_if_fail(record!=NULL, FALSE);
		item = list_entry(record->listpointer, pvr_mgr_list_item, listpointer);

		if(msg_type == PVR_MSG_PLAY_START_GET_HANDLE)//init the plyaback only record's user_data for re-encrypt
		{
			UINT32 len;
			pvr_eng_get_user_data(record->p_handle, item->record_dir_path, item->record_info->puser_data, &len);
			if(item->record_info->puser_data->record_idx == 0) // user data don't save into info yet, need to get it from mgr.
			{
				_pvr_mgr_update_userdata(record->r_handle, (UINT8 *)(item->record_info->puser_data), sizeof(pvr_mgr_user_data));
				pvr_eng_set_user_data(record->r_handle, NULL, item->record_info->puser_data, sizeof(pvr_mgr_user_data));
			}
			_pvr_list_trans_mgr_info(item->record_info->is_update, &item->record_info->record, item->record_info->puser_data);
			return ret;
		}
	}

	if (g_pvr_mgr_info->config.event_callback == NULL)
		return ret;

	switch(msg_type)
	{
		case PVR_MSG_REC_GET_KREC:
		case PVR_MSG_CRYPTO_DATA:
		case PVR_MSG_REC_SET_REENCRYPT_PIDS:
			ret = g_pvr_mgr_info->config.event_callback(handle, msg_type, msg_code);
			break;
		case PVR_MSG_REC_START_OP_STARTDMX:
			if ((item->record_info->record.rec_special_mode == RSM_CAS9_RE_ENCRYPTION) ||
				(item->record_info->record.rec_special_mode == RSM_COMMON_RE_ENCRYPTION) ||
				(item->record_info->record.rec_special_mode == RSM_CAS9_MULTI_RE_ENCRYPTION) ||
				(item->record_info->record.rec_special_mode == RSM_VMX_MULTI_RE_ENCRYPTION) ||
				(item->record_info->record.is_reencrypt && (!item->record_info->record.is_scrambled)))
			{
				pvr_crypto_general_param *rec_param = (pvr_crypto_general_param *)msg_code;
				if (item->record_info->record.rec_special_mode == RSM_CAS9_RE_ENCRYPTION||
                    item->record_info->record.rec_special_mode == RSM_CAS9_MULTI_RE_ENCRYPTION)
				{
					if (!pvr_eng_get_cas9_key_info(handle, rec_param))
					{
						PDEBUG("pvr_eng_get_cas9_krec_info() failed!\n");
						ret = -1;
						break;
					}
				}
				else if ((item->record_info->record.rec_special_mode == RSM_COMMON_RE_ENCRYPTION) ||
						 (item->record_info->record.is_reencrypt && (!item->record_info->record.is_scrambled)))
				{	// save the re-encryption key
					ppvr_mgr_rec_info rec_info = item->record_info;
					MEMCPY(rec_info->puser_data->ciplus_key, rec_param->keys_ptr, (rec_param->key_len+7)/8);
					rec_info->puser_data->key_len = (rec_param->key_len + 7) / 8;
				}
				
				ret = g_pvr_mgr_info->config.event_callback(handle, msg_type, (UINT32)rec_param);
			}
			break;
		case PVR_MSG_REC_STOP_OP_STOPDMX:
			if ((item->record_info->record.rec_special_mode == RSM_CAS9_RE_ENCRYPTION) ||
				(item->record_info->record.rec_special_mode == RSM_COMMON_RE_ENCRYPTION) ||
				(item->record_info->record.rec_special_mode == RSM_CAS9_MULTI_RE_ENCRYPTION) ||
				(item->record_info->record.rec_special_mode == RSM_VMX_MULTI_RE_ENCRYPTION) ||
				(item->record_info->record.is_reencrypt && (!item->record_info->record.is_scrambled)))
			{
				pvr_crypto_general_param rec_param;
				MEMSET(&rec_param, 0, sizeof(pvr_crypto_general_param));
				rec_param.pvr_hnd = handle;
				rec_param.dmx_id = (UINT8)msg_code;
				ret = g_pvr_mgr_info->config.event_callback(handle, msg_type, (UINT32)&rec_param);
			}
			break;
		case PVR_MSG_PLAY_START_OP_STARTDMX:
			if ((item->record_info->record.rec_special_mode == RSM_CAS9_RE_ENCRYPTION) ||
				(item->record_info->record.rec_special_mode == RSM_COMMON_RE_ENCRYPTION) ||
				(item->record_info->record.rec_special_mode == RSM_CAS9_MULTI_RE_ENCRYPTION) ||
				(item->record_info->record.rec_special_mode == RSM_VMX_MULTI_RE_ENCRYPTION) ||
				(item->record_info->record.is_reencrypt && (!item->record_info->record.is_scrambled)))
			{
				if(g_pvr_mgr_info->player_reencrypt_state != 0)
				{
					PDEBUG("Player state trans, skip PVR_MSG_PLAY_START_OP_STARTDMX!\n");
					break;
				}

				UINT16 pid_list[PVR_MAX_PID_NUM];
				pvr_crypto_pids_param pids_param;
				MEMSET(pid_list, 0, sizeof(pid_list));
				MEMSET(&pids_param, 0, sizeof(pvr_crypto_pids_param));
				pids_param.pid_info = &item->record_info->record.pid_info;
				pids_param.pid_list = pid_list;
				pids_param.pid_num = PVR_MAX_PID_NUM;
				g_pvr_mgr_info->config.event_callback(handle,
					PVR_MSG_PLAY_SET_REENCRYPT_PIDS, (UINT32)&pids_param);
				
				pvr_crypto_general_param play_param;
				MEMSET(&play_param, 0, sizeof(pvr_crypto_general_param));
				play_param.pvr_hnd = handle;
				play_param.dmx_id = (UINT8)msg_code;
				play_param.pid_list = pids_param.pid_list;
				play_param.pid_num = pids_param.pid_num;
				play_param.ca_mode = item->record_info->record.ca_mode;

				UINT8 re_encrypt_krec[PVR_CIPLUS_KEY_LEN];
				if (item->record_info->record.rec_special_mode == RSM_CAS9_RE_ENCRYPTION
                    || item->record_info->record.rec_special_mode == RSM_CAS9_MULTI_RE_ENCRYPTION)
				{
					if (!pvr_eng_get_cas9_key_info(handle, &play_param))
					{
						PDEBUG("pvr_eng_get_cas9_krec_info() failed!\n");
						ret = -1;
						break;
					}
				}
				else if ((item->record_info->record.rec_special_mode == RSM_COMMON_RE_ENCRYPTION) ||
						 (item->record_info->record.is_reencrypt && (!item->record_info->record.is_scrambled)))
				{
					MEMCPY(re_encrypt_krec, item->record_info->puser_data->ciplus_key, PVR_CIPLUS_KEY_LEN);
					play_param.key_num = 1;
					play_param.key_len = item->record_info->puser_data->key_len * 8; // measured in bit
					play_param.keys_ptr = re_encrypt_krec;
					play_param.crypto_mode = PVR_CRYPTO_MODE_AES_ECB;
				}
				
				ret = g_pvr_mgr_info->config.event_callback(handle, msg_type, (UINT32)&play_param);
				if (ret != -1)
				{
					g_pvr_mgr_info->player_reencrypt_state = 1;
					if (item->record_info->record.rec_special_mode == RSM_CAS9_RE_ENCRYPTION ||
                     item->record_info->record.rec_special_mode == RSM_CAS9_MULTI_RE_ENCRYPTION)
					{
						pvr_eng_set_cas9_play_key_pos(handle, 
						play_param.crypto_key_pos,play_param.crypto_key_first_pos);
					}
				}
			}
			break;
		case PVR_MSG_PLAY_STOP_OP_STOPDMX:
			if ((item->record_info->record.rec_special_mode == RSM_CAS9_RE_ENCRYPTION) ||
				(item->record_info->record.rec_special_mode == RSM_COMMON_RE_ENCRYPTION) ||
				( item->record_info->record.rec_special_mode == RSM_CAS9_MULTI_RE_ENCRYPTION) ||
				( item->record_info->record.rec_special_mode == RSM_VMX_MULTI_RE_ENCRYPTION) ||
				(item->record_info->record.is_reencrypt && (!item->record_info->record.is_scrambled)))
			{			
				if (g_pvr_mgr_info->player_reencrypt_state != 2)
				{
					PDEBUG("Player state trans, skip PVR_MSG_PLAY_STOP_OP_STOPDMX!\n");
					break;
				}
				pvr_crypto_general_param play_param;
				MEMSET(&play_param, 0, sizeof(pvr_crypto_general_param));
				play_param.pvr_hnd = handle;
				play_param.dmx_id = (UINT8)msg_code;
				ret = g_pvr_mgr_info->config.event_callback(handle, msg_type, (UINT32)&play_param);
				if(ret != -1)
				{
					g_pvr_mgr_info->player_reencrypt_state = 0;
				}
			}
			break;
		case PVR_MSG_PLAY_PTM_UPDATE:
		{
			record_ciplus_uri_item uri;
			INT8 uri_idx = -1;
			BOOL notify = FALSE;

			if(!item->record_info->record.is_reencrypt)
			{
				//PDEBUG("NOT CI+ Recording, PVR_MSG_PLAY_PTM_UPDATE fail!\n");
				break;
			}
			
			// check URI update
			uri_idx = _pvr_mgr_get_ciplus_uri(item, msg_code, &uri);
			if((uri_idx >= 0) && (uri_idx < item->record_info->puser_data->uri_num))//get valid URI
			{
				if(record->p_param1 == -1)//seems no URI be setted before, maybe playback start
				{
					notify = TRUE;
				}
				else if(record->p_param2 == -1)
				{
					if((record->p_param1 + 1) != item->record_info->puser_data->uri_num)
					{
						notify = FALSE;//PERROR("%s ciplus URI usage error!\n", __FUNCTION__);				
					}
				}
				else//flag both be valid
				{
					if(uri_idx != record->p_param1)
					{
						notify = TRUE;
					}
				}
			}
			if(notify)
			{
				record->p_param1 = uri_idx;
				record->p_param2 = ((uri_idx + 1) < item->record_info->puser_data->uri_num) ? (uri_idx + 1) : -1;
				PDEBUG("notify new URI %d at ptm %ds\n", uri_idx, msg_code);
				ret = g_pvr_mgr_info->config.event_callback(handle, PVR_MSG_PLAY_URI_NOTIFY, (UINT32)uri.uDetail);
			}
			}break;
		default:
			ret = g_pvr_mgr_info->config.event_callback(handle, msg_type, msg_code);
			break;
	}
	
	return ret;
}

void printf_hdd_info(struct dvr_HDD_info *partition_info)
{
	struct statvfs stfs;
	UINT32 total_size, free_size;
	fs_statvfs(partition_info->mount_name, &stfs);

	total_size = stfs.f_frsize / 512 * stfs.f_blocks / 2;
	free_size = stfs.f_frsize / 512 * stfs.f_bfree / 2;
	
	libc_printf("partition name %s\n", partition_info->mount_name);
	libc_printf("partition total_size %d(M)\n", partition_info->total_size/1024);
	libc_printf("partition free_size %d(M)\n", partition_info->free_size/1024);
	libc_printf("partition rec_size %d(M)\n", partition_info->rec_size/1024);
	libc_printf("partition tms_size %d(M)\n", partition_info->tms_size/1024);
	libc_printf("hdd total_size %d(M)\n", total_size/1024);
	libc_printf("hdd free_size %d(M)\n", free_size/1024);
}

INT32 _pvr_mgr_fpartition_info(struct dvr_HDD_info *partition_info)
{	
	UINT32 temp;
	struct statvfs stfs;
	char temp_name[16];
	ppvr_mgr_list_item tms_item = NULL;
	pvr_mgr_list *list = NULL;
	BOOL need_reassign_size = FALSE;

    if(partition_info == NULL || strlen(partition_info->mount_name) == 0)
    {
        return 0;
    }

	fs_statvfs(partition_info->mount_name, &stfs);
	//MEMSET(disk_info, 0, sizeof(struct dvr_HDD_info));
	partition_info->total_size = stfs.f_frsize / 512 * stfs.f_blocks / 2;
	partition_info->free_size = stfs.f_frsize / 512 * stfs.f_bfree / 2;
	STRCPY(partition_info->disk_name, stfs.f_device_name);
	MEMSET(temp_name, 0, 16);
	MEMCPY(temp_name, stfs.f_fsh_name, 3);
	if(!_strcasecmp(temp_name, "FAT"))
		partition_info->type = 1;
	else
	{
		MEMCPY(temp_name, stfs.f_fsh_name, 4);
		if(!_strcasecmp(temp_name, "NTFS"))
			partition_info->type = 2;
		else
			partition_info->type = 0;
	}
	if(g_pvr_mgr_info->partition_info.app_alloc_tms_size)
	{
		if(partition_info->free_size >= partition_info->tms_size)
		{
			partition_info->rec_size = partition_info->free_size - partition_info->tms_size;
		}
	}
	else
	{
		temp = partition_info->free_size;
		if(partition_info->disk_usage == PVR_REC_ONLY_DISK)
		{
			partition_info->tms_size = 0;
			partition_info->rec_size = temp;		
		}
		else if(partition_info->disk_usage == PVR_TMS_ONLY_DISK)
		{
			partition_info->tms_size = temp;
			partition_info->rec_size = 0;		
		}
		else
		{
			if(partition_info->tms_size == 0)
			{
				if(g_pvr_mgr_info->config.prj_mode != PVR_DVBS)
				{
		    		UINT32 tms_temp_size = (temp/3)&0xffff1000;	//alined by 4K
		    		if(temp < 1024*1024) // < 1G, cann't do anything. 
		    		{
		    			partition_info->tms_size = 0;
		    			partition_info->rec_size = 0;			
		    		}
		    		else if(tms_temp_size < 1024*1024)
		    		{
		    			partition_info->tms_size = temp;
		    			partition_info->rec_size = 0;
		    		}		
		    		else if(tms_temp_size > 20*1024*1024)
		    		{
		    			partition_info->tms_size = 20*1024*1024;
		    			partition_info->rec_size = partition_info->free_size-partition_info->tms_size;
		    		}	
		    		else
		    		{
		    			partition_info->tms_size = tms_temp_size;
		    			partition_info->rec_size = partition_info->free_size-partition_info->tms_size;
		    		}				
				}
				else
				{
					if(temp < (MIN_PVR_FREESIZE/1024)) // <200M = 0
					{
						partition_info->tms_size = 0;
						partition_info->rec_size = 0;		
					}
					else if(temp < (MIN_TMS_FREESIZE/1024)) // <500M = free
					{
						partition_info->tms_size = temp;
						partition_info->rec_size = 0;		
					}
					else if(temp < (10*1024*1024)) // <10G = 500M
					{
						if(temp < 700*1024) //500~700M
						{
							partition_info->tms_size = temp;
							partition_info->rec_size = 0;	
						}
						else
						{
							partition_info->tms_size = 500*1024;
							partition_info->rec_size = temp - partition_info->tms_size;	
						}
					}
					else if(temp < (20*1024*1024)) // <20G = 1G
					{
						partition_info->tms_size = 1*1024*1024;
						partition_info->rec_size = temp - partition_info->tms_size;		
					}
					else if(temp < (40*1024*1024)) // <40G = 2G
					{
						partition_info->tms_size = 2*1024*1024;
						partition_info->rec_size = temp - partition_info->tms_size;		
					}
					else if(temp < (80*1024*1024)) // <80G = 4G
					{
						partition_info->tms_size = 4*1024*1024;
						partition_info->rec_size = temp - partition_info->tms_size;		
					}
					else // >80G = 8G
					{
						partition_info->tms_size = 8*1024*1024;
						partition_info->rec_size = temp - partition_info->tms_size;		
					}
				}
				partition_info->tms_free = partition_info->tms_size;
			}
			else
			{
				need_reassign_size= TRUE;
			}
		}
	}

	// if there is active tms record item, need add back the tms size!
	if(partition_info->disk_usage == PVR_REC_AND_TMS_DISK)
	{
		list = _pvr_list_get_by_mountname(partition_info->mount_name);
		tms_item = _pvr_list_getitem_byidx(list, TMS_INDEX);
		if((tms_item != NULL) && (tms_item->record_info != NULL))
		{
			REC_ENG_INFO item_info;
			char temp_mount_name[16];
			
			_pvr_mgr_get_mount_name(tms_item->record_dir_path, temp_mount_name);
			if(!STRCMP(partition_info->mount_name, temp_mount_name))
			{
				MEMSET(&item_info, 0, sizeof(REC_ENG_INFO));
				
				pvr_eng_get_record_info(0, tms_item->record_dir_path, &item_info);
				_pvr_list_trans_eng_info(&tms_item->record_info->record, &item_info);

				partition_info->free_size += tms_item->record_info->record.size;
				if(partition_info->free_size < partition_info->tms_size)
				{
					partition_info->tms_size = partition_info->free_size;
				}
			}
			else
			{
				PERROR("%s:%d error!\n", __FUNCTION__, __LINE__);
				SDBBP(); // can't reach this branch!!
			}
		}
	}

	if(need_reassign_size)
	{
		if(partition_info->free_size < partition_info->tms_size)
		{
			partition_info->tms_size = partition_info->free_size;
		}
		partition_info->rec_size = partition_info->free_size - partition_info->tms_size;		
	}
	
	return 0;
}

RET_CODE _pvr_mgr_fpartition_test(struct dvr_HDD_info *partition_info)
{
	int r_speed, w_speed, rw_speed = -1;
	char test_w1_file[256];
	char test_w2_file[256];

	_pvr_mgr_fpartition_info(partition_info);

	partition_info->read_speed = 0;
	partition_info->write_speed = 0;
	partition_info->rw_speed = 0;
	_pvr_mgr_calc_fullpath(partition_info->mount_name, NULL, PVR_TYPE_TEST, 1, test_w1_file);
	_pvr_mgr_calc_fullpath(partition_info->mount_name, NULL, PVR_TYPE_TEST, 2, test_w2_file);
	
	if(partition_info->free_size > (20 * 1024)) //>20M do speed test
	{
		w_speed = __pvr_mgr_do_write_test(test_w1_file);
		_fsync(partition_info->mount_name);
		if(w_speed == -1)
		{
			partition_info->status |= HDDS_WRITE_ERR;
		}
		r_speed = __pvr_mgr_do_read_test(test_w1_file);
		if(r_speed < 0)
		{
			partition_info->status |= HDDS_READ_ERR;
		}

		if(r_speed != -1 && w_speed != -1)
		{
			rw_speed = __pvr_mgr_do_copy(test_w1_file, test_w2_file);
		}
		_fsync(partition_info->mount_name);
		PDEBUG("r_s %d, w_s %d, rw_s %d\n", r_speed, w_speed, rw_speed);

		partition_info->read_speed = (r_speed > 0) ? r_speed : 0;
		partition_info->write_speed = (w_speed > 0) ? w_speed : 0;
		partition_info->rw_speed = (rw_speed > 0) ? rw_speed : 0;

		if(g_pvr_mgr_info->config.cfg_ext.pvr_mode == PVR_REC_RANDOM_FOLDER)
		{
			__pvr_mgr_rm(test_w1_file);
			__pvr_mgr_rm(test_w2_file);
		}
	}
	else
	{
		partition_info->read_speed = 1; //can play rec by default
		partition_info->write_speed = 1;
		partition_info->rw_speed = 1;
		#if 1
		r_speed = __pvr_mgr_do_read_test(test_w1_file);
		if(r_speed == -1)
		{
			// if test file is not exist, read test will be error, 
			// we suppose the r_speed is 1
			r_speed = 1;
		}
		else if(r_speed < 0)
		{
			partition_info->status |= HDDS_READ_ERR;
		}
		partition_info->read_speed = (r_speed > 0) ? r_speed : 0;
		partition_info->status |= HDDS_SPACE_FULL;
		#endif
	}

    PDEBUG("Test disk speed:\n");
    PDEBUG("  read speed :%dMB/s\n",partition_info->read_speed/1024);
    PDEBUG("  write speed:%dMB/s\n",partition_info->write_speed/1024);
    PDEBUG("  rw speed   :%dMB/s\n",partition_info->rw_speed/1024);
	return RET_SUCCESS;
}

RET_CODE _pvr_mgr_prepare_partition(const char *mount_name)
{
	RET_CODE ret = RET_SUCCESS;
	PVR_DIR *dir = NULL;
	char	path[1024];

	_pvr_mgr_calc_fullpath(mount_name, NULL, PVR_TYPE_PREX, 0, path);
	
	dir = _opendir(path);
	if(dir == NULL) //dir not exist
	{
		PDEBUG("open dir %s fail, need make it\n", path);

		{//add for prevent to mkdir into rootfs, found such issue in sata fast plug-poll, maybe run into such trap!
			struct statvfs stfs;
			fs_statvfs(mount_name, &stfs);
			if(!STRCMP(stfs.f_device_name, "sdram"))
			{
				PDEBUG(">>>>>>>>>>>>>>>>>PVR now catch trap for mkdir into rootfs<<<<<<<<<<<<<<<<\n");
				return RET_FAILURE;				
			}
		}
		
		pvr_fs_error(_mkdir(path),  RET_FAILURE); //make an empty pvr dir
		PDEBUG("make dir %s success\n", path);
		dir = _opendir(path);
		if(dir == NULL)
		{
			return RET_FAILURE;
		}
		PDEBUG("open dir %s successs\n", path);
	}
	
	_closedir(dir);

	return ret;
}

void _pvr_mgr_register_partition(struct pvr_register_info *partition)
{
	int i;
	BOOL ret_bool = TRUE;	
	OSAL_T_CTSK task;
	T_CMBF t_cmbf;
	struct pvr_register_info pvr_reg_info;
	ppvr_partition_info partition_info = NULL;
	struct pvr_clean_info cln_info;

	g_pvr_mgr_info->partition_info.app_alloc_tms_size = FALSE;

	MEMCPY(&pvr_reg_info, partition, sizeof(struct pvr_register_info));
	
	g_pvr_mgr_info->register_state = -1;
		
	PDEBUG("start pvr init %s, check list = %d, test speed = %d!\n", pvr_reg_info.mount_name, pvr_reg_info.init_list, pvr_reg_info.check_speed);

	_pvr_mgr_malloc(partition_info, sizeof(pvr_partition_info), 1);

	list_add(&partition_info->listpointer, &g_pvr_mgr_info->partition_info.partition_list);

	partition_info->partition_info.valid = 1;

	_pvr_mgr_get_mount_name(pvr_reg_info.mount_name,partition_info->partition_info.mount_name);
	partition_info->partition_info.disk_usage = pvr_reg_info.disk_usage;
	partition_info->partition_info.init_list = pvr_reg_info.init_list;
	partition_info->partition_info.check_speed = pvr_reg_info.check_speed;
	
	g_pvr_mgr_info->module_state = HDDS_SUCCESS;
	partition_info->partition_info.status = HDDS_SUCCESS;
	
	if(g_pvr_mgr_info->config.cfg_ext.pvr_mode != PVR_REC_RANDOM_FOLDER)
	{
		if(RET_SUCCESS != _pvr_list_add_partition(partition_info->partition_info.mount_name, partition_info->partition_info.init_list))
		{
			ret_bool = FALSE;	
			goto PVR_PART_ERR;
		}
		
		if(partition_info->partition_info.status & HDDS_CREATE_DIR_ERR)
		{
			// disk create root dir failed, disable do any pvr aciton.
			_pvr_mgr_fpartition_info(&(partition_info->partition_info));
			ret_bool = FALSE;	
			goto PVR_PART_ERR;
		}
	}
			
	if(partition_info->partition_info.check_speed == 1)
	{
		if(_pvr_mgr_event(0, PVR_HDD_TEST_SPEED, 0) == 0)
		{
			if(RET_SUCCESS != _pvr_mgr_fpartition_test(&(partition_info->partition_info)))
			{
				PERROR("fs test speed fail!\n");
				ret_bool = FALSE;	
				goto PVR_PART_ERR;
			}
			if((partition_info->partition_info.status & HDDS_READ_ERR) && 
				((partition_info->partition_info.status & HDDS_WRITE_ERR) || (partition_info->partition_info.status & HDDS_SPACE_FULL)))
			{
				// test hdd cann't read write.
				PERROR("fs test speed fail!\n");
				ret_bool = FALSE;	
				goto PVR_PART_ERR;
			}
		}
		else
		{
			_pvr_mgr_fpartition_info(&(partition_info->partition_info));
		}
	}
	else
	{
		_pvr_mgr_fpartition_info(&(partition_info->partition_info));
	}
	
	_pvr_mgr_event(0, PVR_HDD_PVR_CHECK, 0);
	_fsync(partition_info->partition_info.mount_name); //protect disk

	_pvr_mgr_fpartition_info(&(partition_info->partition_info));

PVR_PART_ERR:

	if(!ret_bool)
	{
		PERROR("pvr init error!\n");
		_pvr_mgr_event(0, PVR_HDD_FAIL, 0);
		STRCPY(cln_info.mount_name, pvr_reg_info.mount_name);
		_pvr_mgr_cleanup_partition(&cln_info);
	}
	else
	{
		g_pvr_mgr_info->partition_info.partition_num++;
		
		if(pvr_reg_info.disk_usage == PVR_REC_AND_TMS_DISK)
		{
			g_pvr_mgr_info->partition_info.rec_partition[0] = partition_info;
			g_pvr_mgr_info->partition_info.tms_partition = partition_info;
		}
		else if(pvr_reg_info.disk_usage == PVR_REC_ONLY_DISK)
		{
			g_pvr_mgr_info->partition_info.rec_partition[0] = partition_info;
		}
		else if(pvr_reg_info.disk_usage == PVR_TMS_ONLY_DISK)
		{
			g_pvr_mgr_info->partition_info.tms_partition = partition_info;
		}
		PDEBUG("end pvr init %s!\n", pvr_reg_info.mount_name);
		_pvr_mgr_event(0, PVR_HDD_READY, 0);
		if(g_pvr_mgr_info->config.cfg_ext.pvr_mode != PVR_REC_RANDOM_FOLDER)
		{
			_pvr_mgr_set_partition_use(partition_info->partition_info.disk_usage, partition_info->partition_info.mount_name);
		}
		g_pvr_mgr_info->register_state = 0;
	}

	return;
}

RET_CODE _pvr_mgr_get_tms_hdd(struct dvr_HDD_info *partition_info)
{
    ppvr_partition_info part = g_pvr_mgr_info->partition_info.tms_partition;
    if(part)
    {
        memcpy(partition_info,&part->partition_info,sizeof(struct dvr_HDD_info));
        return RET_SUCCESS;
    }
    return RET_FAILURE;
}


ppvr_partition_info _pvr_mgr_get_partition(const char *mount_name)
{
	INT32 ret = -1;
	struct list_head *ptr;
	ppvr_partition_info partition = NULL;
	UINT16 i;

	//ZZL TODO:
	
    list_for_each(ptr, &g_pvr_mgr_info->partition_info.partition_list)
    {
	    partition = list_entry(ptr, pvr_partition_info, listpointer);

		if(STRCMP(partition->partition_info.mount_name, (char *)mount_name) == 0)
		{
			return partition;
		}
    }	
	return NULL;
}

RET_CODE _pvr_mgr_get_partition_info(char *mount_name, struct dvr_HDD_info *partition_info)
{
	ppvr_partition_info partition = NULL;
	MEMSET(partition_info, 0, sizeof(struct dvr_HDD_info));

	if(mount_name == NULL) //PVR info
	{
		// change to get the fixed disk info
		if(g_pvr_mgr_info->partition_info.rec_partition[0] == NULL)
		{
			if(g_pvr_mgr_info->partition_info.tms_partition == NULL)
			{
				PERROR("%s no partition for pvr use!\n", __FUNCTION__);
				return RET_FAILURE;
			}
			else
			{
				partition = g_pvr_mgr_info->partition_info.tms_partition;
                if(partition == NULL)
                {
                    return RET_FAILURE;
                }
				MEMCPY(partition_info, &partition->partition_info, sizeof(struct dvr_HDD_info));
			}
		}
		else 
		{
			partition = g_pvr_mgr_info->partition_info.rec_partition[0];
            if(partition == NULL)
            {
                return RET_FAILURE;
            }
			MEMCPY(partition_info, &partition->partition_info, sizeof(struct dvr_HDD_info));
			if((g_pvr_mgr_info->partition_info.tms_partition != NULL) && (g_pvr_mgr_info->partition_info.rec_partition[0] != g_pvr_mgr_info->partition_info.tms_partition))
			{
				// replace tms size with tms disk info
				partition = g_pvr_mgr_info->partition_info.tms_partition;
				if (g_pvr_mgr_info->config.cfg_ext.update_tms_space_disable == 0)
					_pvr_mgr_fpartition_info(&partition->partition_info);
				partition_info->tms_size = partition->partition_info.tms_size;
			}
		}
	}
	else // partition info
	{
		ppvr_partition_info temp_partition = NULL;

		temp_partition = _pvr_mgr_get_partition(mount_name);
		if(temp_partition == NULL)
		{
			PERROR("pvr has no partition!\n");
			return RET_FAILURE;
		}
		else
		{
			MEMCPY(partition_info, &temp_partition->partition_info, sizeof(struct dvr_HDD_info));
		}
	}

	return RET_SUCCESS;
}

enum PVR_DISKMODE _pvr_mgr_get_cur_mode(char *rec_partition, char *tms_partition)
{
	enum PVR_DISKMODE ret = PVR_DISK_INVALID;
	ppvr_partition_info partition = NULL;

	if(rec_partition)
		STRCPY(rec_partition, "");
	if(tms_partition)
		STRCPY(tms_partition, "");
	if(g_pvr_mgr_info->partition_info.rec_partition[0] != NULL)
	{
		if(g_pvr_mgr_info->partition_info.tms_partition != NULL)
		{
			if(g_pvr_mgr_info->partition_info.rec_partition[0] == g_pvr_mgr_info->partition_info.tms_partition)
			{
				ret = PVR_DISK_REC_AND_TMS;
				partition = g_pvr_mgr_info->partition_info.rec_partition[0];
				if(rec_partition)
					STRCPY(rec_partition, partition->partition_info.mount_name);
				if(tms_partition)
					STRCPY(tms_partition, partition->partition_info.mount_name);
			}
			else
			{
				ret = PVR_DISK_REC_WITH_TMS;
				partition = g_pvr_mgr_info->partition_info.rec_partition[0];
				if(rec_partition)
					STRCPY(rec_partition, partition->partition_info.mount_name);
				partition = g_pvr_mgr_info->partition_info.tms_partition;
				if(tms_partition)
					STRCPY(tms_partition, partition->partition_info.mount_name);
			}
		}
		else // no tms disk
		{
			ret = PVR_DISK_ONLY_REC;
			partition = g_pvr_mgr_info->partition_info.rec_partition[0];
			if(rec_partition)
				STRCPY(rec_partition, partition->partition_info.mount_name);
		}
	}
	else // no rec disk
	{
		if(g_pvr_mgr_info->partition_info.tms_partition != NULL)
		{
			ret = PVR_DISK_ONLY_TMS;
			partition = g_pvr_mgr_info->partition_info.tms_partition;
			if(tms_partition)
				STRCPY(tms_partition, partition->partition_info.mount_name);
		}
	}

	return ret;
}

RET_CODE _pvr_mgr_set_partition_use(UINT8 use, char *mount_name)
{
	RET_CODE ret = RET_FAILURE;
	ppvr_partition_info partition = NULL;
				
	partition = _pvr_mgr_get_partition(mount_name);
	if(partition == NULL)
	{
		PERROR("%s can not find partition %s!\n", __FUNCTION__, mount_name);
		return ret;
	}

	if(partition->partition_info.disk_usage == use)
	{
		return ret;
	}
	
	partition->partition_info.disk_usage = use;
	
	if(use == PVR_REC_ONLY_DISK)
	{
		g_pvr_mgr_info->partition_info.rec_partition[0] = partition;
		if(g_pvr_mgr_info->partition_info.tms_partition == g_pvr_mgr_info->partition_info.rec_partition[0])
		{
			g_pvr_mgr_info->partition_info.tms_partition = NULL;
		}
		partition->partition_info.tms_size = 0;
		partition->partition_info.rec_size = partition->partition_info.free_size;
	}
	else if(use == PVR_TMS_ONLY_DISK)
	{
		g_pvr_mgr_info->partition_info.tms_partition = partition;
		if(g_pvr_mgr_info->partition_info.rec_partition[0] == g_pvr_mgr_info->partition_info.tms_partition)
		{
			//clear pvr list on this disk
			if(partition->partition_info.init_list)
			{
				_pvr_list_del_partition(partition->partition_info.mount_name);
				partition->partition_info.init_list = 0;
			}
			g_pvr_mgr_info->partition_info.rec_partition[0] = NULL;
		}
		//TODO: make sure all space can be used for tms, 2 ways: 1 is format, other is clean up
		//_cleandir(disk_info->mount_name);
		//_pvr_list_prepare_disk(disk_info->mount_name);
		//pvr_format_HDD(1, mount_name);
		partition->partition_info.tms_size = partition->partition_info.free_size;
		partition->partition_info.rec_size = 0;
		partition->partition_info.write_speed = 20*1024;
		partition->partition_info.read_speed = 20*1024;
		partition->partition_info.rw_speed = 20*1024;
	}
	else if(use == PVR_REC_AND_TMS_DISK)
	{
		if((g_pvr_mgr_info->partition_info.rec_partition[0] != NULL) && (g_pvr_mgr_info->partition_info.rec_partition[0] != partition))
		{
			//clear pvr list on this disk
			if(partition->partition_info.init_list)
			{
				_pvr_list_del_partition(partition->partition_info.mount_name);
			}
		}
		if(g_pvr_mgr_info->partition_info.rec_partition[0] != partition)
		{
			g_pvr_mgr_info->partition_info.rec_partition[0] = partition;
			partition->partition_info.init_list = 1;
			if(RET_SUCCESS != _pvr_list_add_partition(partition->partition_info.mount_name, partition->partition_info.init_list))
			{
				PERROR("set disk use: _pvr_list_add_disk fail!\n");
				return ret;
			}
		}
		g_pvr_mgr_info->partition_info.tms_partition = partition;
		_pvr_mgr_fpartition_info(&(partition->partition_info));
	}

	ret = RET_SUCCESS;
	return ret;
}

INT32 _pvr_mgr_cleanup_all(void)
{
	INT32 ret = -1;
	struct list_head *ptr = NULL, *ptn = NULL;
	ppvr_partition_info partition = NULL;
	UINT16 i;
	struct pvr_clean_info pvr_cln_info;
	
    list_for_each_safe(ptr, ptn, &g_pvr_mgr_info->partition_info.partition_list)
    {
	    partition = list_entry(ptr, pvr_partition_info, listpointer);
		pvr_cln_info.disk_mode = 0;
		STRCPY(pvr_cln_info.mount_name, partition->partition_info.mount_name);
		_pvr_mgr_cleanup_partition(&pvr_cln_info);
    }

	ret = 0;

	return ret;
}

INT32 _pvr_mgr_cleanup_device(char type)
{
	INT32 ret = -1;
	struct list_head *ptr;
	ppvr_partition_info partition = NULL;
	UINT16 i;
	struct pvr_clean_info pvr_cln_info;
	
    list_for_each(ptr, &g_pvr_mgr_info->partition_info.partition_list)
    {
	    partition = list_entry(ptr, pvr_partition_info, listpointer);
		pvr_cln_info.disk_mode = 0;
		if(partition->partition_info.mount_name[5] == type)
		{
			STRCPY(pvr_cln_info.mount_name, partition->partition_info.mount_name);
			_pvr_mgr_cleanup_partition(&pvr_cln_info);
		}
    }

	ret = 0;

	return ret;
}

INT32 _pvr_mgr_cleanup_partition(struct pvr_clean_info *pvr_cln_info)
{
	INT32 ret = -1;
	UINT16 i;
	ppvr_partition_info partition_info = NULL;

	PDEBUG("start pvr cleanup partition %s!\n", pvr_cln_info->mount_name);

	partition_info = _pvr_mgr_get_partition(pvr_cln_info->mount_name);
	if(partition_info == NULL)
	{
		PERROR("pvr has no partition!\n");
		return ret;
	}

	list_del(&partition_info->listpointer);
	g_pvr_mgr_info->partition_info.partition_num--;

	//ZZL TODO: clear all lists under this partition
	if(partition_info->partition_info.init_list)
	{
		_pvr_list_del_partition(partition_info->partition_info.mount_name);
	}

	if((partition_info->partition_info.disk_usage == PVR_REC_AND_TMS_DISK) || (partition_info->partition_info.disk_usage == PVR_TMS_ONLY_DISK))
	{
		//ZZL TODO:
		//if(pvr_configure.continuous_tms_enable)
		//	recorder_clear_continue_tms();
	}
		
	if(g_pvr_mgr_info->partition_info.rec_partition[0] == partition_info) // reset tms disk
	{
		g_pvr_mgr_info->partition_info.rec_partition[0] = NULL;
	}
	if(g_pvr_mgr_info->partition_info.tms_partition == partition_info) // reset tms disk
	{
		g_pvr_mgr_info->partition_info.tms_partition = NULL;
	}

	_pvr_mgr_free(partition_info);

	if(g_pvr_mgr_info->partition_info.partition_num == 0)
	{
		INIT_LIST_HEAD(&g_pvr_mgr_info->partition_info.partition_list);
		for(i=0; i<PVR_MGR_REC_PARTITION_NUM; i++)
		{
			g_pvr_mgr_info->partition_info.rec_partition[i] = NULL;
		}
		g_pvr_mgr_info->partition_info.tms_partition = NULL;
	}
	
	PDEBUG("end pvr cleanup!\n");

	ret =0;
	
	return ret;
}

BOOL _pvr_load_record_listinfo(ppvr_mgr_list_item record_item)
{
	BOOL ret = TRUE;
	REC_ENG_INFO item_info;

	MEMSET(&record_item->record_info->record, 0, sizeof(struct ListInfo));
	MEMSET(&item_info, 0, sizeof(REC_ENG_INFO));

	pvr_eng_get_record_info(0, record_item->record_dir_path, &item_info);

	_pvr_list_trans_eng_info(&record_item->record_info->record, &item_info);
	_pvr_list_trans_mgr_info(record_item->record_info->is_update, &record_item->record_info->record, record_item->record_info->puser_data);

	if(item_info.is_timeshift)
	{
		record_item->record_info->puser_data->record_idx = TMS_INDEX;
		PDEBUG("load a tms record %s\n", record_item->record_dir_path);
	}

	return ret;
}

BOOL _pvr_mgr_add_record(ppvr_mgr_list_item record_item, UINT16 rec_mode)
{
	BOOL ret = TRUE;
	ppvr_mgr_list list = NULL;
	char temp_string[256];

	MEMSET(temp_string, 0, 256);
	_pvr_mgr_get_parent_dir(record_item->record_dir_path, temp_string);
	list = _pvr_list_finddir(temp_string);
	if(list == NULL)
	{
		//create and add to list
		_pvr_list_chgdir(record_item->record_dir_path, 0);
		list = _pvr_list_get_cur_list();
	}

	if(list == NULL)
	{
		ASSERT(0);
	}
	if(rec_mode == RECORDING_TIMESHIFT)
		record_item->record_info->puser_data->record_idx = TMS_INDEX;
	else
		record_item->record_info->puser_data->record_idx = _pvr_list_alloc_index(list);

	record_item->record_info->record_idx = record_item->record_info->puser_data->record_idx;
	_pvr_list_insert_item(list, record_item);
//ZZL TODO: if need to load the list of new dir??
	
	return ret;
}

BOOL _pvr_mgr_add_extfile(ppvr_mgr_list_item record_item)
{
	BOOL ret = TRUE;
	ppvr_mgr_list list = NULL;
	char temp_string[256];

	MEMSET(temp_string, 0, 256);
	STRCPY(temp_string, g_pvr_mgr_info->partition_info.rec_partition[0]->partition_info.mount_name);
	strcat(temp_string, "/");
	strcat(temp_string, g_pvr_mgr_info->config.dvr_path_prefix);

	list = _pvr_list_finddir(temp_string);
	if(list == NULL)
	{
		//create and add to list
		_pvr_list_chgdir(temp_string, 0);
		list = _pvr_list_get_cur_list();
	}

	if(list == NULL)
	{
		ASSERT(0);
	}
	
	record_item->record_info->puser_data->record_idx = _pvr_list_alloc_index(list);
	record_item->record_info->record_idx = record_item->record_info->puser_data->record_idx;
	_pvr_list_insert_item(list, record_item);
	
	return ret;
}

BOOL _pvr_mgr_prepare_user_data(ppvr_mgr_list_item record_item, ppvr_mgr_record_param mgr_param, struct record_prog_param *eng_param)
{
	BOOL ret = TRUE;
	UINT16 i;

	record_item->f_type = F_UNKOWN;
	STRCPY(record_item->record_dir_path, eng_param->folder_name);
	record_item->record_info->dmx_id = eng_param->dmx_id;

	MEMCPY(record_item->record_info->puser_data->channel_name, eng_param->service_name, TXTI_LEN);
	record_item->record_info->puser_data->is_locked = eng_param->lock_flag;
	record_item->record_info->puser_data->record_idx = record_item->record_info->record_idx;
	record_item->record_info->puser_data->ttx_num = eng_param->pid_info.ttx_pid_count;
	record_item->record_info->puser_data->subt_num = eng_param->pid_info.subt_pid_count;
	record_item->record_info->puser_data->ttx_subt_num = eng_param->pid_info.ttx_subt_pid_count;	
	record_item->record_info->puser_data->isdbtcc_num = eng_param->pid_info.isdbtcc_pid_count;	
	record_item->record_info->puser_data->sto_id[0] = eng_param->partition_id[0];	
	record_item->record_info->puser_data->sto_id[1] = eng_param->partition_id[1];	
	for(i=0; ((i<eng_param->pid_info.subt_pid_count) && mgr_param->subt_list); i++)
	{
		MEMCPY(&record_item->record_info->puser_data->subt_array[i], &mgr_param->subt_list[i], sizeof(struct t_subt_lang));
	}
	for(i=0; ((i<eng_param->pid_info.ttx_pid_count) && mgr_param->ttx_list); i++)
	{
		MEMCPY(&record_item->record_info->puser_data->ttx_array[i], &mgr_param->ttx_list[i], sizeof(struct t_ttx_lang));
	}
	for(i=0; ((i<eng_param->pid_info.ttx_subt_pid_count) && mgr_param->ttx_subt_list); i++)
	{
		MEMCPY(&record_item->record_info->puser_data->ttx_subt_array[i], &mgr_param->ttx_subt_list[i], sizeof(struct t_ttx_lang));
	}	
	for(i=0; ((i<eng_param->pid_info.isdbtcc_pid_count) && mgr_param->cclist); i++)
	{
		MEMCPY(&record_item->record_info->puser_data->isdbtcc_array[i], &mgr_param->cclist[i], sizeof(struct t_isdbtcc_lang));
	}
	return ret;
}

BOOL _pvr_mgr_recycle_record(ppvr_mgr_list_item record_item)
{
	BOOL ret = TRUE;
	ppvr_partition_info partition = NULL;
	char mount_name[256];

	_pvr_mgr_get_mount_name(record_item->record_dir_path, mount_name);

	partition = _pvr_mgr_get_partition(mount_name);
	pvr_return_val_if_fail(partition!=NULL, ret);

	partition->partition_info.rec_size += record_item->record_info->record.size;
	partition->partition_info.free_size += record_item->record_info->record.size;
	PDEBUG("recycle record %d size %d(k), now rec_size %d(k)\n", record_item->record_info->record_idx, record_item->record_info->record.size, partition->partition_info.rec_size);

	return ret;
}

BOOL _pvr_mgr_update_userdata(PVR_HANDLE handle, UINT8 *user_data, UINT32 len)
{
	BOOL ret = TRUE;
	ppvr_mgr_active_record record = NULL;
	ppvr_mgr_list_item item = NULL;

	record = _pvr_get_record_byhandle(handle);
	pvr_return_val_if_fail(record!=NULL, FALSE);

    if(record->listpointer)/*add for push-vod --doy, 2011-4-22*/
    {
    	item = list_entry(record->listpointer, pvr_mgr_list_item, listpointer);

    	if((item->record_info->puser_data != NULL) && (item->record_info->is_update))
    	{
    		MEMCPY(user_data, item->record_info->puser_data, len);
    	}
    }
	
	return ret;
}

UINT32 _pvr_mgr_update_record_size(PVR_HANDLE handle, INT32 size)
{
	UINT32 ret = 0xffffffff;
	ppvr_mgr_active_record record = NULL;
	ppvr_mgr_list_item item = NULL;
	ppvr_partition_info partition = NULL;
	char mount_name[256];

	record = _pvr_get_record_byhandle(handle);
	pvr_return_val_if_fail(record!=NULL, ret);
	
	item = list_entry(record->listpointer, pvr_mgr_list_item, listpointer);
	pvr_return_val_if_fail(item!=NULL, ret);

	_pvr_mgr_get_mount_name(item->record_dir_path, mount_name);

	partition = _pvr_mgr_get_partition(mount_name);
	pvr_return_val_if_fail(partition!=NULL, ret);

	if((record->r_handle != 0) && (record->index > TMS_INDEX))
	{
		partition->partition_info.rec_size -= size;
		partition->partition_info.free_size -= size;
		ret = partition->partition_info.rec_size;
		//libc_printf("update size %d(k),%d(q), rec_size %d(k), tms %d(k)\n", size,size/47, partition->partition_info.rec_size, partition->partition_info.tms_size);
	}

	return ret;
}

RET_CODE _pvr_mgr_set_tms_size(UINT32 tms_size, UINT32 tms_file_min_size)
{
	struct dvr_HDD_info *part_info;
	RET_CODE ret = RET_SUCCESS;
	struct statvfs stfs;
	UINT32 real_free_size;

	if (g_pvr_mgr_info->partition_info.tms_partition == NULL)
	{
		return RET_FAILURE;
	}
	
	part_info = &g_pvr_mgr_info->partition_info.tms_partition->partition_info;
	
	if (tms_size > part_info->free_size)
	{
		ret = RET_FAILURE;
	}
	else
	{
		pvr_eng_ioctl(0, PVR_ERIO_CLEAR_TMS, 0, 0);
		g_pvr_mgr_info->partition_info.app_alloc_tms_size = TRUE;
		part_info->tms_size = (tms_size < tms_file_min_size) ? 0 : tms_size;
		if (part_info->disk_usage == PVR_REC_AND_TMS_DISK)
		{
			part_info->rec_size = part_info->free_size - part_info->tms_size;

			fs_statvfs(part_info->mount_name, &stfs);
			real_free_size = stfs.f_frsize / 512 * stfs.f_bfree / 2;
			if(part_info->rec_size > real_free_size)
			{
				part_info->rec_size = real_free_size;
			}
		}
		else
		{
			part_info->rec_size = 0;
		}
		
		PDEBUG("APP adjust: total %dK, free %dK, rec %dK, tms %dK\n", part_info->total_size, part_info->free_size, part_info->rec_size, part_info->tms_size);
	}

	return ret;
}

RET_CODE _pvr_mgr_set_tms_level(UINT8 percent, UINT32 tms_file_min_size)
{
	struct dvr_HDD_info *part_info;
    UINT32 temp_size;

	if (g_pvr_mgr_info->partition_info.tms_partition == NULL)
	{
		return RET_FAILURE;
	}
	
	part_info = &g_pvr_mgr_info->partition_info.tms_partition->partition_info;

	if (part_info->free_size > 100)
	{
        temp_size = (part_info->free_size / 100) * percent;
	}
    else
    {
        temp_size = (part_info->free_size * percent) / 100;
    }

    part_info->tms_level= percent;
	part_info->tms_size = (temp_size < tms_file_min_size) ? 0 : temp_size;
	
	if (part_info->disk_usage == PVR_REC_AND_TMS_DISK)
	{
		part_info->rec_size = part_info->free_size - temp_size;
	}
	else
	{
		part_info->rec_size = 0;
	}
	PDEBUG("APP adjust: total %dK, free %dK, rec %dK, tms %dK\n", part_info->total_size, part_info->free_size, part_info->rec_size, part_info->tms_size);
	return RET_SUCCESS;
}

UINT32 _pvr_mgr_chk_tms_capability(UINT32 ts_bitrate, PTMS_INFO tms_info)
{
	struct dvr_HDD_info *part_info;
	if (g_pvr_mgr_info->partition_info.tms_partition)
		part_info = &g_pvr_mgr_info->partition_info.tms_partition->partition_info;
	else
		return 0;
	
	return _pvr_data_check_tms_capability(ts_bitrate, part_info->tms_size, tms_info);
}


typedef struct _storetable_idx_status
{
	INT32 cur_storetable_idx;
	UINT32 cur_storeinfo_time;
	UINT32 next_storeinfo_time;
	UINT32 section_time;
}storetable_idx_status;

UINT32 total_storetable_idx;
storetable_idx_status store_idx_status;

BOOL _pvr_mgr_data_write_store_info_header(PVR_HANDLE handle,struct store_info_header *sheader)
{

	//get storinfo.dvr//
	UINT32 ret=TRUE;
	ppvr_mgr_active_record record = NULL;
	ppvr_mgr_list_item item = NULL;
	ppvr_partition_info partition = NULL;
	char mount_name[256];
	char string[256];
	
	record = _pvr_get_record_byhandle(handle);
	pvr_return_val_if_fail(record!=NULL, ret);	
	item = list_entry(record->listpointer, pvr_mgr_list_item, listpointer);
	pvr_return_val_if_fail(item!=NULL, ret);
	_pvr_mgr_calc_fullpath(item->record_dir_path, NULL, PVR_TYPE_VMX, 0, string);	
	item->storeinfo_file=_fopen(string, "w+");  //open for write and read

	if(NULL==item->storeinfo_file)
		return FALSE;

	//write info header//
	fseek(item->storeinfo_file, 0, SEEK_SET);
	ret=_fwrite((UINT8 *)sheader, STORE_HEADER_SIZE, item->storeinfo_file);
	fflush(item->storeinfo_file);	
	STOREINFO_DEBUG("==== write storeinfo header done : %s,ret=%d\n",string,ret);
#if 0
	STOREINFO_DEBUG("	====  header length : %d \n",sheader->storeinfoheader_len);
	STOREINFO_DEBUG("	====  header data[0]: %x \n",sheader->storeinfoheader[0]);
	STOREINFO_DEBUG("	====  header data[1]: %x \n",sheader->storeinfoheader[1]);
	STOREINFO_DEBUG("	====  header data[2]: %x \n",sheader->storeinfoheader[2]);
	STOREINFO_DEBUG("	====  header data[3]: %x \n",sheader->storeinfoheader[3]);
	STOREINFO_DEBUG("	====  header data[120]: %x \n",sheader->storeinfoheader[120]);
#endif
	//write ptr info
	UINT8 *buf1=MALLOC(PTR_INFO_SIZE);
	MEMSET(buf1, 0x0,PTR_INFO_SIZE);
	fseek(item->storeinfo_file, INFO_HEADER_LEN+INFO_HEADER_SIZE, SEEK_SET);
	ret=_fwrite((UINT8 *)buf1, PTR_INFO_SIZE, item->storeinfo_file);
	fflush(item->storeinfo_file);	
	FREE(buf1);

	
	UINT8 *buf=MALLOC(STORE_PTR_TABLE_SIZE);
	MEMSET(buf, 0x0,STORE_PTR_TABLE_SIZE);
	fseek(item->storeinfo_file, STORE_HEADER_SIZE, SEEK_SET);
	ret=_fwrite((UINT8 *)buf, STORE_PTR_TABLE_SIZE, item->storeinfo_file);
	fflush(item->storeinfo_file);	
	FREE(buf);
	STOREINFO_DEBUG("==== initialize table  done : ret=%d\n",string,ret);

	fclose(item->storeinfo_file);
	return TRUE;
}

BOOL _pvr_mgr_data_read_store_info_header(ppvr_mgr_list_item item, struct store_info_header *sheader)
{
	//get storinfo.dvr//
	UINT32 ret=TRUE;
	char string[256];
	struct store_info copy_info = {0,0,0,0};
	struct store_info copy_info_next= {0,0,0,0};

	_pvr_mgr_calc_fullpath(item->record_dir_path, NULL, PVR_TYPE_VMX, 0, string);	
	item->storeinfo_file=_fopen(string, "r+");  //open for write and read
	//read info header//

	if(NULL==item->storeinfo_file)
		return FALSE;
	
	fseek(item->storeinfo_file, 0, SEEK_SET);
	ret=_fread((UINT8 *)sheader, INFO_HEADER_LEN+INFO_HEADER_SIZE, item->storeinfo_file);
	
	STOREINFO_DEBUG("==== read storeinfo header done : %s,ret=%d\n",string,ret);
#if 0
	STOREINFO_DEBUG("	====  header length : %d \n",sheader->storeinfoheader_len);
	STOREINFO_DEBUG("	====  header data[0]: %x \n",sheader->storeinfoheader[0]);
	STOREINFO_DEBUG("	====  header data[1]: %x \n",sheader->storeinfoheader[1]);
	STOREINFO_DEBUG("	====  header data[2]: %x \n",sheader->storeinfoheader[2]);
	STOREINFO_DEBUG("	====  header data[3]: %x \n",sheader->storeinfoheader[3]);
	STOREINFO_DEBUG("	====  header data[120]: %x \n",sheader->storeinfoheader[120]);
#endif

	//read total storetable_idx
	fseek(item->storeinfo_file, INFO_HEADER_LEN+INFO_HEADER_SIZE, SEEK_SET);
	ret=_fread((UINT8 *)&total_storetable_idx, 4, item->storeinfo_file);
	STOREINFO_DEBUG("read total_storetable_idx=%d,ret=%d\n",total_storetable_idx,ret);
	// init variables

	store_idx_status.cur_storetable_idx=0;
	fseek(item->storeinfo_file, STORE_HEADER_SIZE+STORE_PTR_SIZE*store_idx_status.cur_storetable_idx, SEEK_SET);
	ret = _fread((UINT8 *)(&copy_info), STORE_PTR_SIZE, item->storeinfo_file);
	store_idx_status.cur_storeinfo_time=copy_info.ptm;

	if(total_storetable_idx!=0)
	{
		fseek(item->storeinfo_file, STORE_HEADER_SIZE+STORE_PTR_SIZE*(store_idx_status.cur_storetable_idx+1), SEEK_SET);
		ret = _fread((UINT8 *)(&copy_info_next), STORE_PTR_SIZE, item->storeinfo_file);
		store_idx_status.next_storeinfo_time=copy_info_next.ptm;		
		store_idx_status.section_time=store_idx_status.next_storeinfo_time-store_idx_status.cur_storeinfo_time;
	}
	else
	{
		store_idx_status.next_storeinfo_time=0;
		store_idx_status.section_time=0;
	}

	fclose(item->storeinfo_file);
	return TRUE;

}


BOOL _pvr_mgr_data_write_storeinfo(PVR_HANDLE handle,struct store_info_data_single*storeinfodata, UINT32 time)
{
	//get storinfo.dvr//
	UINT32 ret=TRUE;
	ppvr_mgr_active_record record = NULL;
	ppvr_mgr_list_item item = NULL;
	ppvr_partition_info partition = NULL;
	char mount_name[256];
	char string[256];
	
	record = _pvr_get_record_byhandle(handle);
	pvr_return_val_if_fail(record!=NULL, ret);	
	item = list_entry(record->listpointer, pvr_mgr_list_item, listpointer);
	pvr_return_val_if_fail(item!=NULL, ret);
	_pvr_mgr_calc_fullpath(item->record_dir_path, NULL, PVR_TYPE_VMX, 0, string);	
	item->storeinfo_file=_fopen(string, "r+");  //open for write and read

	//write total index in header
	fseek(item->storeinfo_file,INFO_HEADER_LEN+INFO_HEADER_SIZE, SEEK_SET);
	ret = _fwrite(&(item->sinfo.index),4, item->storeinfo_file);
	fflush(item->storeinfo_file);
	
	//write storeinfo
	STOREINFO_DEBUG("==== __pvr_data_write_storeinfo====%s\n",string);	

	item->sinfo.ptm=time;
	item->sinfo.encrypt_mode=storeinfodata->encrypt_mode;
	//save index & time & pointer  to table
	//STOREINFO_DEBUG("	>>>> save index & time & pointer to table(sinfo->index=%d ; sinfo->time=%d)\n",item->sinfo.index,item->sinfo.ptm);
	fseek(item->storeinfo_file,STORE_HEADER_SIZE+ STORE_PTR_SIZE* item->sinfo.index, SEEK_SET);  
	ret = _fwrite(&item->sinfo,STORE_PTR_SIZE, item->storeinfo_file);
	fflush(item->storeinfo_file);
	item->sinfo.index++;
	//STOREINFO_DEBUG("	<<<< save index & time & pointer to table done (sinfo->infor_pointer=%d),ret=%d\n",item->sinfo.infor_pointer,ret);


	//save storeinfor len  to data
	//STOREINFO_DEBUG("	>>>> save storeinfor len to data\n");
	fseek(item->storeinfo_file,STORE_HEADER_SIZE+STORE_PTR_TABLE_SIZE+ item->sinfo.infor_pointer , SEEK_SET);  
	ret = _fwrite(&storeinfodata->storeinfodata_len,STORE_INFO_LEN_SIZE, item->storeinfo_file);	 	
	item->sinfo.infor_pointer = item->sinfo.infor_pointer + STORE_INFO_LEN_SIZE ;
	fflush(item->storeinfo_file);			
	//STOREINFO_DEBUG("	<<<< save storeinfor len to data done(sinfo->infor_pointer=%d),ret=%d\n",item->sinfo.infor_pointer,ret);

	//save storeinfo data to data
	//STOREINFO_DEBUG("	>>>> save storeinfo data to data\n");
	fseek(item->storeinfo_file,STORE_HEADER_SIZE+STORE_PTR_TABLE_SIZE+ item->sinfo.infor_pointer , SEEK_SET);  
	ret = _fwrite(&storeinfodata->storeinfodata,storeinfodata->storeinfodata_len, item->storeinfo_file);
	item->sinfo.infor_pointer =item->sinfo.infor_pointer +  storeinfodata->storeinfodata_len ;
	fflush(item->storeinfo_file);			
	//STOREINFO_DEBUG("	<<<< save storeinfo data to data done(sinfo->infor_pointer=%d),ret=%d\n",item->sinfo.infor_pointer,ret);
	
	fclose(item->storeinfo_file);
	return TRUE;
}

BOOL predict_search_index(UINT32 time)
{
	UINT32 time_diff=0;
	UINT32 section_time=0;
	UINT32 predict_step=0;

	if(store_idx_status.section_time ==0)
	{
		return FALSE;	//cannot predict
	}
	else
	{
		section_time=store_idx_status.section_time;
	}
	
	if(store_idx_status.next_storeinfo_time!=0)
	{
		//section_time=store_idx_status.next_storeinfo_time-store_idx_status.cur_storeinfo_time;
		if((time>=store_idx_status.cur_storeinfo_time)&& (time<store_idx_status.next_storeinfo_time))
		{
			STOREINFO_DEBUG("meet cur_storetable_idx\n");
		}
		else if(time>=store_idx_status.next_storeinfo_time)
		{
			time_diff=time-store_idx_status.next_storeinfo_time;
			predict_step=(time_diff/section_time)+1;
			store_idx_status.cur_storetable_idx+=predict_step;

			if(store_idx_status.cur_storetable_idx>total_storetable_idx)
			{
				store_idx_status.cur_storetable_idx=total_storetable_idx;
			}
			STOREINFO_DEBUG("bigger than current idx time_diff=%d, section_time=%d predict_step=%d\n",time_diff,section_time,predict_step);
		}
		else	//smaller than current indx
		{
			time_diff=store_idx_status.cur_storeinfo_time-time;
			predict_step=(time_diff/section_time)+1;
			store_idx_status.cur_storetable_idx-=predict_step;
			if(store_idx_status.cur_storetable_idx<0)
			{
				store_idx_status.cur_storetable_idx=0;
			}
			STOREINFO_DEBUG("smaller than current idx time_diff=%d, section_time=%d, predict_step=%d\n",time_diff,section_time,predict_step);
		}
	}
	else	//last store info
	{
		if(time<store_idx_status.cur_storeinfo_time)
		{
			time_diff=store_idx_status.cur_storeinfo_time-time;
			predict_step=(time_diff/section_time)+1;
			store_idx_status.cur_storetable_idx-=predict_step;
			if(store_idx_status.cur_storetable_idx<0)
			{
				store_idx_status.cur_storetable_idx=0;
			}
			STOREINFO_DEBUG("smaller than current idx time_diff=%d, section_time=%d, predict_step=%d\n",time_diff,section_time,predict_step);
		}
	}
	
	return TRUE;
}

BOOL _pvr_mgr_data_read_storeinfo(ppvr_mgr_list_item item, struct store_info_data*storeinfodata, UINT32 time)
{
	//get storinfo.dvr//
	UINT32 ret=TRUE;
	char string[256];
	UINT32 count =0;
	struct store_info *copy_info = NULL;
	struct store_info *copy_info_next = NULL;
	#define PREDICT_LOOP_COUNT	3

	_pvr_mgr_calc_fullpath(item->record_dir_path, NULL, PVR_TYPE_VMX, 0, string);	
	
	item->storeinfo_file=_fopen(string, "r+");  //open for write and read
	STOREINFO_DEBUG("==== __pvr_data_read_storeinfo====%s\n",string);	
	

	copy_info = (struct store_info *)MALLOC(sizeof(struct store_info));
	if(copy_info == NULL)
		return NULL;
	
	MEMSET(copy_info, 0, sizeof(struct store_info));

	copy_info_next = (struct store_info *)MALLOC(sizeof(struct store_info));
	if(copy_info_next == NULL)
		return NULL;
	
	MEMSET(copy_info_next, 0, sizeof(struct store_info));
	
	STOREINFO_DEBUG("	< input time= %d > \n",time);

	// total_storetable_idx is increasing when timeshift or replay recording file	
	//read total storetable_idx
	if(NULL == item->storeinfo_file)
	{
		FREE(copy_info);
		FREE(copy_info_next);
		return NULL;
	}
	
	fseek(item->storeinfo_file, INFO_HEADER_LEN+INFO_HEADER_SIZE, SEEK_SET);
	ret=_fread((UINT8 *)&total_storetable_idx, 4, item->storeinfo_file);
	STOREINFO_DEBUG("read total_storetable_idx=%d,ret=%d\n",total_storetable_idx,ret);
	
	predict_search_index(time);
	
	do
	{
		//get pointer by time in table//
		fseek(item->storeinfo_file, STORE_HEADER_SIZE+STORE_PTR_SIZE*store_idx_status.cur_storetable_idx, SEEK_SET);
		ret = _fread((UINT8 *)copy_info, STORE_PTR_SIZE, item->storeinfo_file);
		store_idx_status.cur_storeinfo_time=copy_info->ptm;

		fseek(item->storeinfo_file, STORE_HEADER_SIZE+STORE_PTR_SIZE*(store_idx_status.cur_storetable_idx+1), SEEK_SET);
		ret = _fread((UINT8 *)copy_info_next, STORE_PTR_SIZE, item->storeinfo_file);
		store_idx_status.next_storeinfo_time=copy_info_next->ptm;
		if(store_idx_status.next_storeinfo_time!=0)
		{
			store_idx_status.section_time=store_idx_status.next_storeinfo_time-store_idx_status.cur_storeinfo_time;			
		}
		count++;
		STOREINFO_DEBUG("	< cindex= %d , cptm=%d,cpointer=%d,cur_idx=%d, count=%d>\n",copy_info->index,copy_info->ptm,copy_info->infor_pointer,store_idx_status.cur_storetable_idx,count);
	
		if (time>=copy_info->ptm)
		{					
			
			if((time<copy_info_next->ptm) ||((copy_info_next->index==0)&&(copy_info_next->ptm==0)&&(copy_info_next->infor_pointer==0)))
			{
				STOREINFO_DEBUG(" 	*** data found..........\n");
				//infor_pointer_pre=copy_info->infor_pointer;
				fseek(item->storeinfo_file,STORE_HEADER_SIZE+STORE_PTR_TABLE_SIZE+ copy_info->infor_pointer, SEEK_SET);				
				ret = _fread(&storeinfodata->store_info_data_pre.storeinfodata_len, STORE_INFO_LEN_SIZE, item->storeinfo_file);
				ret = _fread(&storeinfodata->store_info_data_pre.storeinfodata, storeinfodata->store_info_data_pre.storeinfodata_len, item->storeinfo_file);
				storeinfodata->store_info_data_pre.time=copy_info->ptm;
				storeinfodata->store_info_data_pre.encrypt_mode=copy_info->encrypt_mode;
				
				//STOREINFO_DEBUG(" ***  copy_info->infor_pointer=%d,read len=%d\n",copy_info->infor_pointer,ret);
				//STOREINFO_DEBUG(" 	*** store_time = %d\n",storeinfodata->store_info_data_pre.time);
			#if 0
				STOREINFO_DEBUG(" 	*** store_data = %d\n",storeinfodata->store_info_data_pre.storeinfodata_len);
				STOREINFO_DEBUG(" 	*** storeinfo[0] = %d\n",storeinfodata->store_info_data_pre.storeinfodata[0]);
				STOREINFO_DEBUG(" 	*** storeinfo[4] = %x\n",storeinfodata->store_info_data_pre.storeinfodata[4]);
				STOREINFO_DEBUG(" 	*** storeinfo[5] = %x\n",storeinfodata->store_info_data_pre.storeinfodata[5]);
				STOREINFO_DEBUG(" 	*** storeinfo[13] = %x\n",storeinfodata->store_info_data_pre.storeinfodata[13]);
			#endif
				if((copy_info_next->index==0)&&(copy_info_next->ptm==0)&&(copy_info_next->infor_pointer==0))
				{
					storeinfodata->store_info_data_nex.time=0;
					storeinfodata->store_info_data_nex.storeinfodata_len=0;
					storeinfodata->store_info_data_nex.encrypt_mode=0;
					STOREINFO_DEBUG(" 	*** next data not stored..........\n");
				}
				else
				{
					fseek(item->storeinfo_file,STORE_HEADER_SIZE+STORE_PTR_TABLE_SIZE+ copy_info_next->infor_pointer, SEEK_SET);				
					ret = _fread(&storeinfodata->store_info_data_nex.storeinfodata_len, STORE_INFO_LEN_SIZE, item->storeinfo_file);
					ret = _fread(&storeinfodata->store_info_data_nex.storeinfodata, storeinfodata->store_info_data_nex.storeinfodata_len, item->storeinfo_file);
					storeinfodata->store_info_data_nex.time=copy_info_next->ptm;
					storeinfodata->store_info_data_nex.encrypt_mode=copy_info_next->encrypt_mode;

					//STOREINFO_DEBUG(" *** copy_info_next->infor_pointer=%d,read len=%d\n",copy_info_next->infor_pointer,ret);
					//STOREINFO_DEBUG(" 	*** store_time = %d\n",storeinfodata->store_info_data_nex.time);
				#if 0
					STOREINFO_DEBUG(" 	*** store_data = %d\n",storeinfodata->store_info_data_nex.storeinfodata_len);
					STOREINFO_DEBUG(" 	*** storeinfo[0] = %d\n",storeinfodata->store_info_data_nex.storeinfodata[0]);
					STOREINFO_DEBUG(" 	*** storeinfo[4] = %x\n",storeinfodata->store_info_data_nex.storeinfodata[4]);
					STOREINFO_DEBUG(" 	*** storeinfo[5] = %x\n",storeinfodata->store_info_data_nex.storeinfodata[5]);
					STOREINFO_DEBUG(" 	*** storeinfo[13] = %x\n",storeinfodata->store_info_data_nex.storeinfodata[13]);
				#endif
				}
			
				break;
			}
			
			STOREINFO_DEBUG("forward search\n");

			if(count<=PREDICT_LOOP_COUNT)
			{
				predict_search_index(time);
			}
			else
			{
				if(store_idx_status.cur_storetable_idx<total_storetable_idx)
				{
					store_idx_status.cur_storetable_idx++;
				}
			}

		}
		else
		{
			STOREINFO_DEBUG("backward search\n");

			if(count<=PREDICT_LOOP_COUNT)
			{
				predict_search_index(time);
			}
			else
			{
				if(store_idx_status.cur_storetable_idx!=0)
				{
					store_idx_status.cur_storetable_idx--;
				}
			}
		}
	}while(1);
	FREE(copy_info);
	FREE(copy_info_next);
	//STOREINFO_DEBUG("	quit_read....\n");
	
	fclose(item->storeinfo_file);
	return 1;	
}
